#include "RosterGroup.h"

#include "XMPPConnection.h"
#include "RosterEntry.h"
#include "PacketCollector.h"
#include "SmackConfiguration.h"

#include <packet/IQ.h>
#include <packet/RosterPacket.h>

#include <filter/PacketIDFilter.h>

#include <util/StringUtils.h>


RosterGroup::RosterGroup(std::string & name, XMPPConnection * connection) :
	name(name),
	connection(connection)
{ }


void RosterGroup::setName(std::string & name) {
	//synchronized (entries) {
	for (std::list<RosterEntry*>::iterator it = entries.begin(); 
			it != entries.end(); it++) {
		RosterPacket * packet = new RosterPacket();
		packet->setType(IQ::IQ_TYPE_SET);
		RosterPacket::Item * item = RosterEntry::toRosterItem(*it);
		item->removeGroupName(this->name);
		item->addGroupName(name);
		packet->addRosterItem(item);
		connection->sendPacket(packet);
		
	}
	//}
}


RosterEntry * RosterGroup::getEntry(std::string & user) {
	if (user.empty()) {
		return NULL;
	}
	// Roster entries never include a resource so remove the resource
	// if it's a part of the XMPP address.
	std::string userLowerCase = StringUtils::parseBareAddress(user);
	std::transform(userLowerCase.begin(), userLowerCase.end(), userLowerCase.begin(), ::tolower);
	//synchronized (entries) {
	for (std::list<RosterEntry*>::iterator it = entries.begin();
			it != entries.end(); it++) {
		if ((*it)->getUser() == userLowerCase) {
			return *it;
		}
	}
	//}
	return NULL;
}


bool RosterGroup::contains(RosterEntry * entry) {
	//synchronized (entries) {
	return entries.end() != std::find( entries.begin(), entries.end(), entry);
}


void RosterGroup::addEntry(RosterEntry * entry) {
	PacketCollector * collector = NULL;
	// Only add the entry if it isn't already in the list.
	//synchronized (entries) {
	if ( entries.end() == std::find( entries.begin(), entries.end(), entry)) {
		RosterPacket * packet = new RosterPacket();
		packet->setType(IQ::IQ_TYPE_SET);
		RosterPacket::Item * item = RosterEntry::toRosterItem(entry);
		item->addGroupName(getName());
		packet->addRosterItem(item);
		// Wait up to a certain number of seconds for a reply from the server.
		collector = connection->createPacketCollector(
				new PacketIDFilter(packet->getPacketID()));
		connection->sendPacket(packet);
	}
	//}
	if (collector != NULL) {
		IQ * response = (IQ*) collector->nextResult(SmackConfiguration::getPacketReplyTimeout());
		collector->cancel();
		if (response == NULL) {
			//throw new XMPPException("No response from the server.");
		}
		// If the server replied with an error, throw an exception.
		else if (response->getType() == IQ::IQ_TYPE_ERROR) {
			//throw new XMPPException(response.getError());
		}
		// Add the new entry to the group since the server processed the request successfully
		addEntryLocal(entry);
	}
}


void RosterGroup::removeEntry(RosterEntry * entry) {
	PacketCollector * collector = NULL;
	// Only remove the entry if it's in the entry list.
	// Remove the entry locally, if we wait for RosterPacketListenerprocess>>Packet(Packet)
	// to take place the entry will exist in the group until a packet is received from the 
	// server.
	//synchronized (entries) {
	if ( entries.end() != std::find( entries.begin(), entries.end(), entry)) {
		RosterPacket * packet = new RosterPacket();
		packet->setType(IQ::IQ_TYPE_SET);
		RosterPacket::Item * item = RosterEntry::toRosterItem(entry);
		item->removeGroupName(this->getName());
		packet->addRosterItem(item);
		// Wait up to a certain number of seconds for a reply from the server.
		collector = connection->createPacketCollector(
				new PacketIDFilter(packet->getPacketID()));
		connection->sendPacket(packet);
	}
	//}
	if (collector != NULL) {
		IQ * response = (IQ*) collector->nextResult(SmackConfiguration::getPacketReplyTimeout());
		collector->cancel();
		if (response == NULL) {
			//throw new XMPPException("No response from the server.");
		}
		// If the server replied with an error, throw an exception.
		else if (response->getType() == IQ::IQ_TYPE_ERROR) {
			//throw new XMPPException(response.getError());
		}
		// Remove the entry locally since the server processed the request successfully
		removeEntryLocal(entry);
    }
}


void RosterGroup::addEntryLocal(RosterEntry * entry) {
	// Only add the entry if it isn't already in the list.
	//synchronized (entries) {
	std::remove(entries.begin(), entries.end(), entry);
	entries.push_back(entry);
	//}
}


void RosterGroup::removeEntryLocal(RosterEntry * entry) {
	// Only remove the entry if it's in the entry list.
	//synchronized (entries) {
	std::remove(entries.begin(), entries.end(), entry);
	//}
}


